/* -----------------------------------------------
 *       Filename:  server.c
 *         Author:  MIEN
 *    Description:  处理请求的http服务端
 *           Date:  2016-11-20
 * ----------------------------------------------- */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include "../lib/dict.h"
#include "../lib/rect.h"
#include "../config.h"
#include "../queue.h"
#include "../factory.h"
#include "http.h"
#include "server.h"

/* 存储 http 请求的矩形表 */
static rect_table_t *_h_; 

/* 把 fd 转为 rect_key_t 类形 */
#define RECT_KEY(fd) ((rect_key_t) (unsigned int) (fd))

/* 当前要处理的http请求 */
static http_entity_t *_http;

/* 存储GET、POST等方法指针的字典 */
static dictTable *_c_;  

#include "_get.c"
#include "_post.c"
#include "_head.c"
#include "_sub.c"
#include "_unsub.c"
#include "_stat.c"

/* 初始 */
void initServer()
{
    /* 定义支持的HTTP的方法 */
    _c_ = dictCreate(&dictTypeStringKey);
    dictSet(_c_, "GET", _httpGet);
    dictSet(_c_, "POST", _httpPost);
    dictSet(_c_, "PUT", _httpPost);
    dictSet(_c_, "HEAD", _httpHead);
    dictSet(_c_, "SUB", _httpSub);
    dictSet(_c_, "UNSUB", _httpUnsub);
    dictSet(_c_, "STAT", _httpStat);

    /* 由于fd在连接多时依次增大，在空闲时又依次减小，
     * 所以把列数(宽度)定义的小，把行数(高度)定义的大，是合适的 */
    _h_ = rect_create_with_size(16, 128);
}

/* 释放 */
void freeServer()
{
    dictFree(_c_);
    rect_free(_h_);
}

/* 解析HTTP完成以后，处理具体请求 */
static void http_serve_handle(http_entity_t *http) {
    
    if (http->status == 200) {
        char *config_auth = getConfig("queue_auth");
        if (config_auth != NULL) {
            char *client_auth = http_get_header(http, "Auth");
            if (client_auth == NULL || strcmp(config_auth, client_auth)) {
                http_set_status(http, 401);
            }
        }        
    }

    if (http->status == 200) {
        httpCommand *cmd = dictGet(_c_, http->method);
        if (cmd == NULL) {
            http_set_status(http, 405);
        } else {
            http_reset_buffer(http);
            cmd(http);
        }
    }
}

/* 处理输入事件 */
void httpServeIn(int fd)
{
    _http = rect_get(_h_, RECT_KEY(fd));

    if (_http == NULL) {
        _http = malloc(sizeof(http_entity_t));
        rect_set(_h_, RECT_KEY(fd), _http);
        http_set_step(_http, IDLE);
    }

    if (_http->step == IDLE) {
        http_init(_http);
        http_set_step(_http, READ);
    }

    if (_http->step == READ) {
        http_read(_http, fd);
    }

    if (_http->step == WRITE) {
        http_parse(_http);
        http_serve_handle(_http);
        http_response(_http, fd);
        http_discard(_http, fd);
        http_close(_http, fd);
        http_set_step(_http, IDLE);
    }
}

/* 处理输出事件 */
void httpServeOut(int fd)
{
}
